package com.pic.mgt.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

public class IgxFileUtils {
	
	public static final String redetectFileTmpSuffixStringForWindowsUse = "_$";
	
	/**
	 * 讓檔案重新被偵測。Linux: 利用 open OutputStream 再close 的方式 ; Winodws: 利用 rename 為暫存檔，再將
	 * 暫存檔 rename 回原來的檔方式。(不支援 Linux 和 Windows 以外的作業系統)
	 * @param file
	 * @throws IOException
	 */
	public static void redetectFile(File file) throws IOException {
		String osName = RunTimeSystemUtils.getRuntimeOS();
		
		if (osName.indexOf("linux") >= 0) {
			// 表示執行環境為 Linux 作業系統
			
			if (!file.exists()) {
				throw new FileNotFoundException("File '" + file.getAbsolutePath() + "' does not exist.");
			}
			else {
				OutputStream out = new FileOutputStream(file, true);
				out.close();
			}
		}
		else if (osName.indexOf("windows") >= 0) {
			// 表示執行環境為 Windows 作業系統
			
			File tmpFile = new File(file.getAbsolutePath() + redetectFileTmpSuffixStringForWindowsUse);
			
			// Rename 為暫存的檔名
			file.renameTo(tmpFile);
			
			// Rename 回原來的檔名
			tmpFile.renameTo(file);
		}
		else {
			throw new IOException("Re-detect file only supports OS 'Linux' or 'Windows'.");
		}
	}
	
	/**
	 * 將 redetect 的暫存檔,重新命名回為原來的檔名
	 * @param redetectTmpFile
	 */
	public static void renameRedetectTmpFileToOrigin(File redetectTmpFile) {
		File originalFile = new File(StringUtils.removeEnd(
											redetectTmpFile.getAbsolutePath(),
											redetectFileTmpSuffixStringForWindowsUse));
		
		// Rename 回原來的檔名
		redetectTmpFile.renameTo(originalFile);
	}
	
	/**
	 * 測試是否能取得檔案Lock，若不行表示檔案有其它程序在使用中，並拋出 IOException。
	 * @param confirmationFile
	 * @throws IOException
	 */
	public static void testFileLock(File confirmationFile)
												throws IOException {
		// 採用 File Lock 的方法,來探測檔案是否已經完成傳輸。
		FileChannel channel = null;
		try {
			// throws IOException
			channel = new RandomAccessFile(confirmationFile, "rw").getChannel();
			FileLock lock;
			try {
				// throws OverlappingFileLockException ,IOException
				lock = channel.tryLock();
				if (null == lock) {
					throw new IOException(
							"The file '" + confirmationFile.getAbsolutePath() +
							"' can't be opened to read or write, because it has been locked in this thread or jvm."
					);
				}
				else {
					// 取到鎖定後立即釋放(表示確認檔已完成傳輸)
					// throw IOException
					lock.release();
				}
			} catch (OverlappingFileLockException e) {
				throw new IOException(
						"The file '" + confirmationFile.getAbsolutePath() +
						"' can't be opened to read or write, because it has been locked in this thread or jvm."
				);
			}
		} catch (IOException e) {
			throw e;
		} finally {
			if (null != channel) {
				channel.close();
			}
		}
	}
	
	/**
	 * 依據給定的目錄，列出目錄底下所有包含的目錄。
	 * @param path
	 * @return
	 */
	// (送多方新增)
	public static List<File> listDirectory(File path) {
		List<File> directoryList = new LinkedList<File>();
		
		File[] filesArray = path.listFiles();
		if (null != filesArray) {
			for (File file : filesArray) {
				if (file.isDirectory()) {
					directoryList.add(file);
				}
			}
			return directoryList;
		}
		else {
			return directoryList;
		}
	}
}
